Vue之Provide/Inject使用和源码分析

您所在的位置:网站首页 vue project inject Vue之Provide/Inject使用和源码分析

Vue之Provide/Inject使用和源码分析

2023-03-13 16:56| 来源: 网络整理| 查看: 265

概念和使用

Vue的通信中,有一种方法是用来横跨曾祖组件之间进行通信的,这种方式就是通过Vue 提供的Provide/Inject 来实现的。

provide:Object | () => Object,祖先组件中数据注入。inject:Array | { [key: string]: string | Symbol | Object },子孙组件中数据获取。使用方法:

祖先组件

// 父级组件提供 'foo' {{ foo }} import Children from './children' export default { data(){ return { object:{ name:'' } } } provide(){ return { object:this.object } }, components:{ Children } }

子孙组件

this is a children {{ object.name }} export default { inject:['object'] }

provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的 property 还是可响应的

源码解析代码入口//src\core\instance\index.js import { initMixin } from './init' // _init方法,初始化data/props/methods/computed/watch/provide/inject等 initMixin(Vue) export default Vue

进入到initMixin方法里面,可以看到initInjections方法,这里就是对inject的处理,下面我们来看一下这个方法做了什么事情?

initInjections方法//src\core\instance\inject.js export function initInjections (vm: Component) { // 获取可用的provide数据,并返回搜索结果 const result = resolveInject(vm.$options.inject, vm) if (result) { //设置shouldObserve=false,在底下 defineReactive调用的时候,不将数据进行响应式处理 toggleObserving(false) Object.keys(result).forEach(key => { /* istanbul ignore else */ defineReactive(vm, key, result[key]) }) toggleObserving(true) } }

首先在进入initInjections方法后,会根据当前的inject的数据,去向上查找父级中的provide的数据值,并将搜索内容返回。

查找到数据以后,通过toggleObserving方法将shouldObserve=false,这样的作用是通知defineReactive不要将内容转换成响应式。

那么,initInjections方法是如何实现的呢?

在开始之前,我们要先了解一个知识点,Vue.js实例化的第一步是格式化用户传入的数据,会按照一定的规则去转换我们的数据,inject也是一样,比如

//我们设置的inject的格式 { inject:['object'] } //格式化以后的inject的数据格式 { inject:{ object:{ from:'foo' } } }

因此,我们要是需要获取inject的数据,需要通过inject[key].from获取父级中的provide的数据。

如果循环结束后source为空,那么可以确定provide没有提供相应值注入,这时候就需要读取inject中配置的默认值。如果'default' in inject[key],证明配置了默认值,如果没有,将会在生产环境下打印警告。通过inject[key].default读取到provideDefault,但是默认值是支持函数和普通字符串的,这个时候需要判断provideDefault是不是函数,如果是就执行它并将结果存入result中;如果不是就直接将provideDefault存入result中

// 从provide中获取inject需要的数据 export function resolveInject (inject: any, vm: Component): ?Object { if (inject) { //创建一个空对象 const result = Object.create(null) //获取inject的所有key值 const keys = hasSymbol ? Reflect.ownKeys(inject) : Object.keys(inject) //遍历keys for (let i = 0; i 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted。所以initProvide的调用在initState之后,同样可以保证子级能够获取到父级的provide的数据。

initProvide方法

那我们再来看一下initProvide方法做了什么事情?

export function initProvide (vm: Component) { const provide = vm.$options.provide if (provide) { vm._provided = typeof provide === 'function' ? provide.call(vm) : provide } }

initProvide做的事情其实很简单,就是获取provide 数据,判断provide是否函数,函数则调用获取数据,并改变this指向,非函数则直接赋值,将最终数据挂到_provided 中。

总结

最后,我们对provide/inject的实现方式进行一个总结。

provide将数据进行代理,代理到_provided中,供下游的子级节点使用。而子级则通过inject[injectKey].from的方式,不断地向上级的_provided去查找,直到找到数据源,再将数据返回供子级使用。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3